#!/usr/bin/python

import socket
import select
import struct

EXT_PORT = 21112

LOCAL_PORT = 11112
GAME_PORT = 3658

REMOTE_SERVER = ( "127.0.0.1", 21112 )
LOCAL_SERVER = ( "127.0.0.1", 11112 )

r_clients = set([REMOTE_SERVER])
l_clients = set([])


def handle_remote_data(lsock, rs_sock):
	global r_clients
	
	# MAX frame size is 65535, but std i-net MTU is 1500++
	# we'll default to 64k just to be safe
	data, client = rs_sock.recvfrom(65535)

	if data:
		print "remote data from {0} on {1}".format(client, rs_sock.getsockname())

		# placing the dest port in the first 2 bytes of the data
		new_port = struct.unpack(">H", data[0:2])

		# add the remote client to the list of clients, 
		# in case it doesn't already exist

		if not client in r_clients:
			r_clients.add(client)

		for c in l_clients:
			if new_port[0] == LOCAL_PORT:
				temp = c
			else:
				temp = (c[0], new_port[0])

			print "sending data to local {0} on {1}".format(temp, ls_sock.getsockname())
			if new_port[0] == LOCAL_PORT:
				ls_sock.sendto(data[2:], temp)
			elif new_port[0] == GAME_PORT:
				game_sock.sendto(data[2:], temp)
			else:
				lsock.sendto(data[2:], temp)

		return False

	return True

def handle_local_data(ls_sock, rs_sock):
	global l_clients
	
	# MAX frame size is 65535, but std i-net MTU is 1500++
	# we'll default to 64k just to be safe
	data, client = ls_sock.recvfrom(65535)

	if data:
		sock_info = ls_sock.getsockname()
		print "local data from {0} on {1}".format(client, sock_info)
		# add the remote client to the list of clients, 
		# in case it doesn't already exist
		if not client in l_clients:
			print "adding local client {0}".format(client)
			l_clients.add(client)

		# prepending the dest port in the first 2 bytes of data
		full_data = struct.pack(">H", sock_info[1]) + data
		for c in r_clients:
			print "sending data to remote {0} on {1}".format(c, rs_sock.getsockname())
			rs_sock.sendto(full_data, c)

		return False

	return True

# MAIN 
# throwaway socket for getting IP address
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("gmail.com",80))
local_ip = s.getsockname()[0]

rs_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM )
rs_sock.bind( (local_ip, EXT_PORT) )

ls_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ls_sock.bind( (local_ip, LOCAL_PORT) )

game_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
game_sock.bind( (local_ip, GAME_PORT) )

socks = [rs_sock, ls_sock, game_sock]

print "Red Dead Repeater v0.1 - CLIENT"

while 1:
	ins, outs, whats = select.select(socks, socks, socks)

	problem = False
	for s in ins:
		if s == ls_sock:
			problem |= handle_local_data(ls_sock, rs_sock)
		elif s == rs_sock:
			problem |= handle_remote_data(ls_sock, rs_sock)
		elif s == game_sock:
			problem |= handle_local_data(game_sock, rs_sock)
	
	for s in whats:
		print "EXCEPTION ON SOCK {0}".format(s)
